package com.kl.component.shiro;

import com.alibaba.fastjson.JSON;
import com.kl.modular.system.dao.bo.SystemAdminBo;
import com.kl.modular.system.dao.bo.SystemRoleBo;
import com.kl.modular.system.dao.model.SystemAdmin;
import com.kl.modular.system.dao.model.SystemRole;
import com.kl.modular.system.service.api.ISystemAdminRoleService;
import com.kl.modular.system.service.api.ISystemAdminService;
import com.kl.modular.system.service.api.ISystemAuthResourceService;
import com.kl.modular.system.service.api.ISystemRoleService;
import com.kl.modular.system.service.constant.SystemConStant;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * apache shrio 认证与授权
 * @author zjb
 * @date 2015/08/12 21:36
 */
public class MonitorRealm extends AuthorizingRealm {
	
	private static final Logger logger = LoggerFactory.getLogger(MonitorRealm.class);
	
	@Autowired
	private ISystemAdminService sytemAdminService;

	
	@Autowired
	private ISystemRoleService systemRoleService;
	
	@Autowired
	private ISystemAuthResourceService systemAuthResourceSerice;
	
	@Autowired
	private SysmanCredentialsMatcher credentialsMatcher;

	
	public MonitorRealm() {
		super();
		setAuthenticationTokenClass(CaptchaUsernamePasswordToken.class);
	}

    /**
     * 登录授权
     */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		logger.info("登录授权>>authToken:"+JSON.toJSONString(authcToken));
		// 验证验证码
		CaptchaUsernamePasswordToken tokens= (CaptchaUsernamePasswordToken)authcToken;
		Subject currentUser = SecurityUtils.getSubject();
		SimpleAuthenticationInfo saInfo = null;
		if(StringUtils.equals(tokens.getType(), CaptchaUsernamePasswordToken.TYPE_SYS)){
			String imgCodeRight = currentUser.getSession().getAttribute("imgCode").toString();
			String imgCode = tokens.getCaptcha();
			if(StringUtils.isEmpty(tokens.getCode())){}
			if ((StringUtils.isEmpty(imgCode))
					|| (!(imgCode.trim().toLowerCase().equals(imgCodeRight)))) {
				throw new IncorrectCaptchaException();
			}
			SystemAdminBo systemAdminBo = new SystemAdminBo();
			systemAdminBo.setAdminUserName(tokens.getUsername());
			SystemAdmin systemAdmin = sytemAdminService.getSystemAdminByBo(systemAdminBo);
			if(systemAdmin == null){
				//没有该用户
				throw new UnknownAccountException("No account found for user [" + tokens.getUsername() + "]");
			}
			if(StringUtils.equals(systemAdmin.getStatus(), SystemConStant.SYSTEM_ADMIN_STATUS_LOCKED)){
				// 当前用户被锁
				throw new AuthLockException("this account is locked");
			}
			saInfo = new SimpleAuthenticationInfo(tokens.getUsername(), tokens.getPassword(), getName());
		}
		if(StringUtils.equals(tokens.getType(), CaptchaUsernamePasswordToken.TYPE_ACCOUNT)){
			saInfo = new SimpleAuthenticationInfo(tokens.getUsername(), System.currentTimeMillis(), getName());
		}
		return saInfo;
	}	

	/**
     * 制定权限授权
     */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		logger.info("制定权限授权>>authToken:"+JSON.toJSONString(principals));
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		String userName = (String) principals.fromRealm(getName()).iterator().next();
		Session session = SecurityUtils.getSubject().getSession();
		AuthorityUser authUser = (AuthorityUser) session.getAttribute((SystemConStant.SESSION_USER_KEY));

		// 角色信息
		String [] roleCodes = authUser.getRoleCodes().toString().split(",");
		SystemRoleBo roleBo = new SystemRoleBo();
		roleBo.setRoleCodes(roleCodes);
		List<SystemRole> roleList = systemRoleService.getListByBo(roleBo);
		if(roleList == null || roleList.size() == 0){
			return null;
		}
		List<String> permissionCodeAllList = new ArrayList<String>();
		// 角色权限
		for(int j = 0;j<roleList.size();j++){
			SystemRole role = roleList.get(j);
			info.addRole(role.getRoleShrioCode());
			permissionCodeAllList = addPermissionRoleCodeList(role.getRoleCode(), permissionCodeAllList);
		}
		// 去除重复制定权限
		List<String> permissionCodeNewAllList = new ArrayList<String>();
		for(String s: permissionCodeAllList){
			if(Collections.frequency(permissionCodeNewAllList, s) < 1) permissionCodeNewAllList.add(s);
		}

		// 制定权限
		info.addStringPermissions(permissionCodeNewAllList);

		System.out.println("当前拥有权限：" + JSON.toJSONString(permissionCodeNewAllList));
		return info;
	}


	/**
	 * 角色制定权限
	 * @param roleCode
	 * @param permissionCodeAllList
     * @return
     */
	public List<String> addPermissionRoleCodeList(String roleCode, List<String> permissionCodeAllList){
		Session session = SecurityUtils.getSubject().getSession();
		AuthorityUser authUser = (AuthorityUser) session.getAttribute((SystemConStant.SESSION_USER_KEY));
		if(StringUtils.isEmpty(roleCode)){
			return permissionCodeAllList;
		}
		String moduleType = authUser.getUserType();
		List<String> permissionCodeList = systemAuthResourceSerice.getRoleAuthListByRoleCode(roleCode, moduleType);
		if(permissionCodeList == null){
			return permissionCodeAllList;
		}
		permissionCodeAllList.addAll(permissionCodeList);
		return permissionCodeAllList;
	}


	/**
	  * 更新用户授权信息缓存.
	  */
	 public void clearCachedAuthorizationInfo(String principal) {
		 SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
		 clearCachedAuthorizationInfo(principals);
	 }
	 
	/**
	 * 清除所有用户授权信息缓存.
	 */
	public void clearAllCachedAuthorizationInfo() {
		Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
		if (cache != null) {
			for (Object key : cache.keys()) {
				cache.remove(key);
			}
		}
	}
	
	/**
	 * 设定Password校验.
	 */
	@PostConstruct
	public void initCredentialsMatcher() {
		setCredentialsMatcher(credentialsMatcher);
	}

}